//
//  StudyViewController.swift
//  SitPosition
//
//  Created by apple on 2019/2/3.
//  Copyright © 2019 apple. All rights reserved.
//

import Foundation
import UIKit
import Typist
import Toast_Swift
import FSPagerView
import Cartography
import SDWebImage
import INSPhotoGallery


/**
 * 核心学习模块
 */
let videoPreviewContainerH: CGFloat = 211
let historySnapshotContainerH: CGFloat = 70
let poseTipViewH: CGFloat = 30

let imageWidth: CGFloat = 368
let imageHeight: CGFloat = 368

let kPoseImageCell: String = "poseImageCell"
let kPoseThumbnailCell: String = "poseThumbnailCell"

class StudyViewController : GKNavigationBarViewController {
    
    // MARK: - Types
    
    // 状态机
    enum State {
        case initial
        case correcting
        case studying
    }
    
    // MARK: - Properties
    
    // 键盘管理
    private let keyboard: Typist = Typist()
    // TTS引擎
    private let ttsEngine: TTSEngine = TTSEngine()
    
    // 上半部分不包含聊天视图的容器视图
    private var topHalfContainer: UIView = UIView()
    private var topHalfContainerTopConstraintGroup: ConstraintGroup!
    private var topHalfContainerHeightConstraintGroup: ConstraintGroup!
    
    // 图片、视频预览根容器
    private lazy var previewContainer: TouchableView = {
        let view = TouchableView()
        view.onDoubleTap = { [unowned self] in
            self.isMaximumPreview = !self.isMaximumPreview
            self._maxminPreviewView(self.isMaximumPreview, true)
        }
        return view
    }()
    private var isMaximumPreview: Bool = false
    // 大图浏览器
    private lazy var poseImageView: UIImageView = {
        let iv = UIImageView(frame: previewContainer.bounds)
        iv.contentMode = UIView.ContentMode.scaleAspectFill
        iv.clipsToBounds = true
        return iv
    }()
    // 视频采集器
    private lazy var VA: VideoActor = {
        let va = VideoActor()
        va.delegate = self
        va.videoGravity = .resizeAspect
        return va
    }()
    private lazy var SSDPL: SSPipeline = {
        let pipeline = SSPipeline()
        pipeline.humanChangedHandler = { [weak self] (hasNobody) in
            DispatchQueue.main.async {
                if hasNobody {
                    self?.hasHuman = false
                    self?._humanChanged()
                    self?._poseChanged()
                }
            }
        }
        return pipeline
    }()
    private lazy var CMPL: CMPipeline = {
        let pipeline = CMPipeline(size: CGSize(width: imageWidth, height: imageHeight))
        
        // 配置CMPL
        pipeline.humanChangedHandler = { [weak self] (hasNobody) in
            DispatchQueue.main.async {
                self?.hasHuman = !hasNobody
                self?._humanChanged()
                if !hasNobody {
                    self?._poseChanged()
                }
            }
        }
        pipeline.poseChangedHandler = { [weak self] (pose, image) in
            DispatchQueue.main.async {
                if (self?.pose ?? PoseType.ok) != pose {
                    self?.pose = pose
                    self?._poseChanged()
                }
                StudyStateMachine.instance.queue(pose, image: image)
            }
        }
        return pipeline
    }()
    // 位置引导图
    private lazy var poseGuideImageView: UIImageView = {
        let iv = UIImageView(image: UIImage(named: "auxiliary"))
        iv.contentMode = UIView.ContentMode.scaleAspectFill
        return iv
    }()
    // 当前是否检测到人体?
    private var hasHuman: Bool = false
    // 当前检测到的姿态
    private var pose: PoseType = PoseType.ok
    // 状态机
    private var state: State = State.initial
    // 坐姿矫正迟延任务
    private var delayCheckCorrectPoseTask: Task? = nil
    // 退出App迟延任务
    private var delayExitAppTask: Task? = nil
    // 自动黑屏迟延任务
    private var delayToggleBrightnessTask: Task? = nil
    // 屏幕默认亮度
    private var defaultBrightness: CGFloat = UIScreen.main.brightness
    private var newBrightness: CGFloat = UIScreen.main.brightness
    // 学习计时器
    private var studyTimer: Timer? = nil
    private var studyBeginTime: Date = Date()
    // 当前正在报警标志
    private var isAlarming: Bool = false
    
    // 历史快照容器
    private let historySnapshotContainer: UIView = UIView()
    // 缩略图列表
    private lazy var poseThumbsPagerView: FSPagerView = {
        let pager = FSPagerView(frame: historySnapshotContainer.bounds)
        pager.isInfinite = false
        pager.interitemSpacing = 15
        pager.automaticSlidingInterval = 0
        pager.itemSize = CGSize(width: 50, height: 50)
        pager.dataSource = self
        pager.delegate = self
        pager.register(PoseThumbnailPagerViewCell.self, forCellWithReuseIdentifier: kPoseThumbnailCell)
        return pager
    }()
    
    // 坐姿状态提示
    private let poseTipView: StudyPoseTipView = StudyPoseTipView()
    // 环信聊天容器
    private let ringIMContainer: UIView = UIView()
    // 环信聊天子控制器
    private lazy var ringIMVC: EaseMessageViewController? = nil
    
    // 家长端最近半小时数据快照
    private var isLastPage: Bool = false    // 最后一页标志
    private var studySnapshots: [StudySnapshot] = [] {
        didSet {
            // 同步姿态信息提示Banner
            if let value = studySnapshots.first?.type {
                pose = PoseType(networkValue: value) ?? PoseType.ok
                _poseChanged()
            }
        }
    }
    // 七牛上传OSS
    private var qiniuBuckets: QiniuBuckets? = nil
    
    // MARK: - Object lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        
        // 导航栏
        gk_navBackgroundColor = UIColor.clear
        gk_navLeftBarButtonItem = UIBarButtonItem(imageName: "ic_nav_back", target: self, action: #selector(_backButtonTapped))
        gk_navRightBarButtonItem = UIBarButtonItem(imageName: "study_set", target: self, action: #selector(_studySettingsButtonTapped))
        
        // 子视图
        setupUIs()
        
        // 管理键盘
        keyboard.on(event: Typist.KeyboardEvent.willShow) { [weak self] (options) in
            self?._maxminMessageView(true, options, true)
        }.on(event: Typist.KeyboardEvent.willHide) { [weak self] (options) in
            self?._maxminMessageView(false, options, true)
        }.start()
        
        // 其它初始任务...
        switch UserManager.manager.role {
        case .parent:
            break
        case .student:
            NotificationCenter.default
                .addObserver(forName: StudyStateMachine.triggerAlarmNotification,
                             object: nil, queue: OperationQueue.main) { [weak self] (note) in
                self?._handelTriggerAlarmNotification(note)
            }
            // 矫正坐姿
            _correctPose()
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        if let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.onSendEvent = { [weak self] _ in
                guard let sself = self else { return }
                // 有任何触摸事件发生就立即恢复屏幕亮度
                sself._toggleBrightness(sself.defaultBrightness, true)
            }
        }
        if UserManager.manager.role == .student {
            UIApplication.shared.isIdleTimerDisabled = true
            try? VA.start()
        } else {
            UIApplication.shared.isIdleTimerDisabled = false
        }
        super.viewDidAppear(animated)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.onSendEvent = nil
        }
        if UserManager.manager.role == .student {
            VA.stop()
        }
        ttsEngine.stopSpeaking()
        UIApplication.shared.isIdleTimerDisabled = false
    }
    
    deinit {
        studyTimer?.invalidate()
        studyTimer = nil
        cancelTask(delayExitAppTask)
        cancelTask(delayCheckCorrectPoseTask)
        cancelTask(delayToggleBrightnessTask)
        keyboard.stop()
        keyboard.clear()
        NotificationCenter.default.removeObserver(self)
    }
}

// MARK: - VideoActorDelegate

extension StudyViewController : VideoActorDelegate {
    
    func videoActorNotGrantPermission() {
        let alert = UIAlertController(title: Strings.noPermissionToAccessCamera, message: nil, preferredStyle: UIAlertController.Style.alert)
        alert.addAction(UIAlertAction(title: Strings.ok, style: UIAlertAction.Style.default, handler: { (_) in
            guard let url: URL = URL(string: UIApplication.openSettingsURLString),
                UIApplication.shared.canOpenURL(url) else {
                return
            }
            let options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:]
            UIApplication.shared.open(url, options: options, completionHandler: nil)
        }))
        alert.addAction(UIAlertAction(title: Strings.cancel, style: UIAlertAction.Style.cancel, handler: nil))
        present(alert, animated: true, completion: nil)
    }
    
    func videoActorDidOutput(_ sampleBuffer: CMSampleBuffer) {
        SSDPL.runCoreML(sampleBuffer) { [weak self] (personImage) in
            guard let image: UIImage = personImage else {
                return
            }
            self?.CMPL.runCoreML(image)
        }
    }
}

// MARK: - FSPagerViewDelegate

extension StudyViewController : FSPagerViewDataSource, FSPagerViewDelegate {
    
    func numberOfItems(in pagerView: FSPagerView) -> Int {
        return studySnapshots.count
    }
    
    func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
        let screenScale: CGFloat = UIScreen.main.scale
        let snapshot: StudySnapshot = studySnapshots[index]
        let url: URL? = URL(string: snapshot.url)
        
        switch pagerView {
        case poseThumbsPagerView:
            let cell = pagerView.dequeueReusableCell(withReuseIdentifier: kPoseThumbnailCell, at: index)
            cell.imageView?.qiniu_setImage(url, placeholder: UIImage(named: "placeholder_small"),
                                           maxSize: 50*screenScale,
                                           animated: true)
            cell.imageView?.contentMode = .scaleAspectFill
            cell.imageView?.clipsToBounds = true
            cell.textLabel?.text = snapshot.timeString
            cell.setNeedsLayout()
            return cell
        default:
            fatalError("Should not reach here")
        }
    }
    
    func pagerView(_ pagerView: FSPagerView, didSelectItemAt index: Int) {
        switch pagerView {
        case poseThumbsPagerView:
            // 同步大图显示
            _syncPoseImageView(at: index)
            poseThumbsPagerView.scrollToItem(at: index, animated: true)
        default:
            fatalError("Unexpected FSPagerView event")
        }
        
        // 同步姿态信息提示Banner
        self.pose = PoseType(networkValue: studySnapshots[index].type) ?? PoseType.ok
        self._poseChanged()
    }
    
}

// MARK: -

extension StudyViewController : EaseMessageViewControllerDataSource {
    
    func messageViewController(_ viewController: EaseMessageViewController!, modelFor message: EMMessage!) -> IMessageModel! {
        let model: EaseMessageModel = EaseMessageModel(message: message)
        if let chatCacheInfo: ChatUserCacheInfo = ChatUserCacheInfo.query(by: message.from) {
            model.nickname = chatCacheInfo.nickName
            model.avatarURLPath = chatCacheInfo.avatarUrl
        }
        model.avatarImage = UIImage(named: "EaseUIResource.bundle/user")
        model.failImageName = "imageDownloadFail"
        return model
    }
}

// MARK: - Private Methods

extension StudyViewController {
    
    // 顶部top标志
    private static func _isTopUseSafeAreaLayoutGuide() -> Bool {
        if #available(iOS 11.0, *) {
            let frame = UIApplication.shared.statusBarFrame
            if CGFloat.minimum(frame.width, frame.height) > 20 {
                return true
            }
        }
        return false
    }
    
    // 根据当前用户角色来配置页面
    fileprivate func setupUIs() {
        view.addSubviews([
            topHalfContainer,
            ringIMContainer
            ])
        
        // 家长端
        switch UserManager.manager.role {
        case .parent:
            // 配置子视图
            topHalfContainer.addSubviews([
                previewContainer,
                historySnapshotContainer,
                poseTipView
            ])
            previewContainer.addSubview(poseImageView)
            historySnapshotContainer.addSubview(poseThumbsPagerView)
            
            // 图片预览视图
            constrain(poseImageView, previewContainer) { (v, parent) in
                v.edges == parent.edges
            }
            constrain(poseThumbsPagerView, historySnapshotContainer) { (v, parent) in
                v.edges == parent.edges
            }
            
            // 获取学生最近半⼩小时的姿态数据
            DispatchQueue.main.async { [weak self] in
                self?._fetctHalfHourDataOfStudent()
            }
        case .student:
            // 配置子视图
            poseTipView.onTap = { [weak self] in
                self?.view.endEditing(true)
            }
            topHalfContainer.addSubviews([
                previewContainer,
                poseTipView
            ])
            
            // 视频输出视图
            let renderView = VA.renderView
            previewContainer.addSubview(renderView)
            constrain(renderView, previewContainer) { (v, parent) in
                v.edges == parent.edges
            }
            previewContainer.addSubview(poseGuideImageView)
            constrain(poseGuideImageView, previewContainer) { (v, parent) in
                v.edges == parent.edges
            }
            #if ENABLE_RENDER_DEBUG
            // 视频输出视图
            CMPL.renderView = previewContainer
            #endif
        }
        _setupContraints()
        
        // 环信聊天子VC
        _setupMessageView()
    }
    
    // 设置聊天视图
    private func _setupMessageView() {
        var ringIMPeerID: String? = nil
        switch UserManager.manager.role {
        case UserRole.student:
            ringIMPeerID = UserManager.manager.user?.parentIMAccount?.id
        case UserRole.parent:
            ringIMPeerID = UserManager.manager.user?.studentIMAccount?.id
        }
        guard let ringIMPeerID_ = ringIMPeerID else {
            return
        }
        if let vc = EaseMessageViewController(conversationChatter: ringIMPeerID_, conversationType: EMConversationTypeChat) {
            vc.dataSource = self
            vc.view.frame = ringIMContainer.bounds
            vc.willMove(toParent: self)
            addChild(vc)
            ringIMContainer.addSubview(vc.view)
            vc.didMove(toParent: self)
            ringIMVC = vc
            
            constrain(vc.view, ringIMContainer) { (v, parent) in
                v.edges == parent.edges
            }
        }
    }
    
    // 设置视图约束
    private func _setupContraints() {
        // topHalfContainer
        
        constrain(topHalfContainer, view) { (v, parent) in
            v.left == parent.left
            v.right == parent.right
        }
        
        // topHalfContainerTopConstraintGroup
        topHalfContainerTopConstraintGroup = ConstraintGroup()
        constrain(topHalfContainer, replace: topHalfContainerTopConstraintGroup) { (v) in
            if StudyViewController._isTopUseSafeAreaLayoutGuide() {
                v.top == v.superview!.safeAreaLayoutGuide.top
            } else {
                v.top == v.superview!.top
            }
        }
        
        // topHalfContainerHeightConstraintGroup
        topHalfContainerHeightConstraintGroup = ConstraintGroup()
        switch UserManager.manager.role {
        case .parent:
            constrain(topHalfContainer, replace: topHalfContainerHeightConstraintGroup) { (v) in
                v.height == (videoPreviewContainerH + historySnapshotContainerH + poseTipViewH)
            }
        case .student:
            constrain(topHalfContainer, replace: topHalfContainerHeightConstraintGroup) { (v) in
                v.height == (videoPreviewContainerH + poseTipViewH)
            }
        }
        
        switch UserManager.manager.role {
        case .parent:
            // videoPreviewContainer
            constrain(previewContainer, topHalfContainer) { (v, parent) in
                v.top == parent.top
                v.left == parent.left
                v.right == parent.right
                v.bottom == parent.bottom - historySnapshotContainerH - poseTipViewH
            }
            
            // historySnapshotContainer
            constrain(historySnapshotContainer, topHalfContainer) { (v, parent) in
                v.left == parent.left
                v.bottom == parent.bottom - poseTipViewH
                v.right == parent.right
                v.height == historySnapshotContainerH
            }
            
            // poseTipView
            constrain(poseTipView, topHalfContainer) { (v, parent) in
                v.left == parent.left
                v.bottom == parent.bottom
                v.right == parent.right
                v.height == poseTipViewH
            }
        case .student:
            // videoPreviewContainer
            constrain(previewContainer, topHalfContainer) { (v, parent) in
                v.top == parent.top
                v.left == parent.left
                v.right == parent.right
                v.height == parent.height - poseTipViewH
            }
            
            // poseTipView
            constrain(poseTipView, topHalfContainer) { (v, parent) in
                v.left == parent.left
                v.bottom == parent.bottom
                v.right == parent.right
                v.height == poseTipViewH
            }
        }
        
        // ringIMContainer
        constrain(ringIMContainer, topHalfContainer, view) { (v, sibling, parent) in
            v.top == sibling.bottom
            v.left == parent.left
            v.right == parent.right
            if #available(iOS 11.0, *) {
                v.bottom == parent.safeAreaLayoutGuide.bottom
            } else {
                v.bottom == parent.bottom
            }
        }
    }
    
    // 延迟设置屏幕亮度
    // @brightness - 屏幕亮度
    // @ rightNow - 是否立即设置屏幕亮度
    private func _toggleBrightness(_ brightness: CGFloat, _ rightNow: Bool) {
        guard newBrightness != brightness && UIScreen.main.brightness != brightness else {
            return
        }
        newBrightness = brightness
        let blackScreenTI: Int = UserConfigs.current?.blackScreenTime ?? UserConfigs.defaultBlackScreenTime // 单位：秒
        
        cancelTask(delayToggleBrightnessTask)
        delayToggleBrightnessTask = nil
        
        let taskBlock = {
            DispatchQueue.main.async {
                if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
                    appDelegate.graduallySetBrightness(brightness)
                }
            }
        }
        
        if rightNow {
            taskBlock()
        } else {
            delayToggleBrightnessTask = delay(TimeInterval(blackScreenTI), task: taskBlock)
        }
    }
    
    // 最大、最小视频、图片预览视图
    private func _maxminPreviewView(_ maximum: Bool, _ flush: Bool) {
        var height: CGFloat = 0
        switch UserManager.manager.role {
        case .parent:
            height = (videoPreviewContainerH + historySnapshotContainerH + poseTipViewH)
        case .student:
            height = (videoPreviewContainerH + poseTipViewH)
        }
        
        if maximum {
            constrain(topHalfContainer, replace: topHalfContainerHeightConstraintGroup) { (v) in
                v.height == v.superview!.height
            }
            ringIMContainer.isHidden = true
        } else {
            constrain(topHalfContainer, replace: topHalfContainerHeightConstraintGroup) { (v) in
                v.height == height
            }
            ringIMContainer.isHidden = false
        }
        if flush {
            UIView.animate(withDuration: 0.5, animations: view.layoutIfNeeded)
        }
    }
    
    // 最大、最小聊天视图
    private func _maxminMessageView(_ maximum: Bool, _ options: Typist.KeyboardOptions, _ flush: Bool) {
        var ty: CGFloat = 0
        switch UserManager.manager.role {
        case .parent:
            ty = (videoPreviewContainerH + historySnapshotContainerH + poseTipViewH)
        case .student:
            ty = (videoPreviewContainerH + poseTipViewH)
        }

        if maximum {
            constrain(topHalfContainer, replace: topHalfContainerTopConstraintGroup) { (v) in
                v.top == v.superview!.top - ty
            }
        } else {
            constrain(topHalfContainer, replace: topHalfContainerTopConstraintGroup) { (v) in
                if StudyViewController._isTopUseSafeAreaLayoutGuide() {
                    v.top == v.superview!.safeAreaLayoutGuide.top
                } else {
                    v.top == v.superview!.top
                }
            }
        }
        _maxminPreviewView(false, false)
        
        if flush {
            UIView.animate(withDuration: 0.5, animations: view.layoutIfNeeded)
        }
    }
    
    // 完成坐姿初次矫正
    private func _correctPose() {
        state = State.correcting
        ttsEngine.speak(TTSSpeechUtterance.plainText(Strings.studyCorrectPose))
        _delayCheckCorrectPose()
    }
    
    private func _delayCheckCorrectPose() {
        cancelTask(delayCheckCorrectPoseTask)
        delayCheckCorrectPoseTask = nil
        
        delayCheckCorrectPoseTask = delay(5) { [weak self] in
            self?._checkCorrectPose()
        }
    }
    
    // 完成坐姿初次矫正并通过TTS播报结果，直到矫正完成
    @objc
    private func _checkCorrectPose() {
        if !hasHuman {
            ttsEngine.speak(TTSSpeechUtterance.plainText(Strings.studyNobodyHere))
            _delayCheckCorrectPose()
            return
        }
        if pose.isOk {
            ttsEngine.speak(TTSSpeechUtterance.plainText(Strings.studyKeepupGoodPose))
            state = State.studying
            
            // 开始学习计时
            _startStudyTimer()
            // 进入学习状态后启动屏幕亮度调节延迟任务
            _toggleBrightness(0, false)
            return
        } else {
            let placeholder: String = pose.description
            let s: String = Strings.studyPoseWrongTip.replacingOccurrences(of: "$SLANT", with: placeholder)
            ttsEngine.speak(TTSSpeechUtterance.plainText(s))
            _delayCheckCorrectPose()
        }
    }
    
    // 人体变化
    private func _humanChanged() {
        switch state {
        case State.initial: break
        case State.correcting: break
        case State.studying:
            if hasHuman {
                _cancelExitApp()
            } else {
                _delayExitApp()
            }
        }
    }
    
    // 开始学习计时
    private func _startStudyTimer() {
        guard studyTimer == nil else { return }
        let timer = Timer(timeInterval: 10, repeats: true) { [weak self] (timer) in
            guard let sself = self else { return }
            
            let studyTime: Int = UserConfigs.current?.studyTime ?? UserConfigs.defaultStudyTime
            let duration: Double = abs(sself.studyBeginTime.timeIntervalSinceNow)
            sself.studyBeginTime = Date()
            
            if duration >= Double(studyTime) {
                DispatchQueue.main.async {
                    self?._triggerStudyTimeAlarm()
                }
            }
        }
        studyTimer = timer
        RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
    }
    
    // 触发学习时长报警
    private func _triggerStudyTimeAlarm() {
        ttsEngine.speak(TTSSpeechUtterance.plainText(Strings.studyTimeAlarm))
    }
    
    // 人离开后延迟3分钟退出应用
    private func _delayExitApp() {
        guard delayExitAppTask == nil else {
            return
        }
        cancelTask(delayExitAppTask)
        delayExitAppTask = nil
        
        delayExitAppTask = delay(3*60, task: {
            abort()
        })
    }
    
    private func _cancelExitApp() {
        cancelTask(delayExitAppTask)
        delayExitAppTask = nil
    }
    
    // 姿态变化
    private func _poseChanged() {
        switch UserManager.manager.role {
        case .parent:
            poseTipView.noData = studySnapshots.isEmpty
            poseTipView.hasHuman = true
        case .student:
            poseTipView.noData = false
            poseTipView.hasHuman = hasHuman
        }
        poseTipView.type = pose
    }
    
    // 获取学生最近半⼩小时的姿态数据
    private func _fetctHalfHourDataOfStudent() {
        #if false
        let url: String = "http://setting.sheel.cn/80EE2C60-9DEC-4F7C-A37F-830A00151FE1"
        let uploadTime: Int64 = Int64(Date(timeIntervalSinceNow: -3*24*3600).timeIntervalSince1970*1000)
        studySnapshots = [
            StudySnapshot(id: "1", type: 1, url: url, uploadTime: uploadTime+60*1000),
            StudySnapshot(id: "2", type: 2, url: url, uploadTime: uploadTime+2*60*1000),
            StudySnapshot(id: "3", type: 3, url: url, uploadTime: uploadTime+3*60*1000),
            StudySnapshot(id: "4", type: 4, url: url, uploadTime: uploadTime+4*60*1000),
            StudySnapshot(id: "5", type: 5, url: url, uploadTime: uploadTime+5*60*1000),
            StudySnapshot(id: "6", type: 6, url: url, uploadTime: uploadTime+6*60*1000),
            StudySnapshot(id: "7", type: 3, url: url, uploadTime: uploadTime+7*60*1000),
            StudySnapshot(id: "8", type: 2, url: url, uploadTime: uploadTime+8*60*1000),
            StudySnapshot(id: "9", type: 1, url: url, uploadTime: uploadTime+9*60*1000),
            StudySnapshot(id: "10", type: 4, url: url, uploadTime: uploadTime+10*60*1000)
        ]
        isLastPage = true
        poseThumbsPagerView.reloadData()
        _syncPoseImageView(at: 0)
        #else
        view.makeToastActivity(ToastPosition.center)
        let date: Date = Date(timeIntervalSinceNow: -30*60)
        NetworkClient.instance.fetchStudentHalfHourPoseData(startTime: date, pageNum: 0, success: { [weak self] (data) in
            self?.view.hideToastActivity()
            guard let data_ = data else {
                self?.view.makeToast(Strings.unexpectedResponseError)
                return
            }
            do {
                let decoder: JSONDecoder = JSONDecoder()
                let pagableData: PagableData<StudySnapshot> = try decoder.decode(PagableData<StudySnapshot>.self, from: data_)
                if let contents = pagableData.content {
                    self?.studySnapshots = contents
                }
                self?.isLastPage = pagableData.last ?? false
                self?.poseThumbsPagerView.reloadData()
                self?._syncPoseImageView(at: 0)
            } catch {
                self?.view.makeToast(Strings.unexpectedResponseError)
            }
        }) { [weak self] (error) in
            self?.view.hideToastActivity()
            self?.view.makeToast(error?.localizedDescription ?? Strings.networkError)
        }
        #endif
    }
    
    // 同步大图显示
    private func _syncPoseImageView(at index: Int) {
        guard (0..<studySnapshots.count).contains(index) else {
            return
        }
        let screenScale: CGFloat = UIScreen.main.scale
        let screenWidth: CGFloat = CGFloat.minimum(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
        
        let snapshot: StudySnapshot = studySnapshots[index]
        let url: URL? = URL(string: snapshot.url)
        poseImageView.qiniu_setImage(url, placeholder: UIImage(named: "placeholder_lager"),
                                     maxSize: screenWidth*screenScale,
                                     animated: true)
    }
    
    // 手工发送环信消息
    private func _sendEMMessage(_ text: String) {
        ringIMVC?.sendTextMessage(text)
    }
    
    // 返回按钮点击事件
    private func _popup() {
        if presentingViewController != nil {
            dismiss(animated: true, completion: nil)
        } else {
            navigationController?.popViewController(animated: true)
        }
    }
    
    @objc private func _backButtonTapped() {
        guard UserManager.manager.role == UserRole.student else {
            _popup()
            return
        }
        let alert: UIAlertController = UIAlertController(title: Strings.studyQuitConfirm, message: nil, preferredStyle: UIAlertController.Style.alert)
        alert.addAction(UIAlertAction(title: Strings.yes, style: UIAlertAction.Style.destructive, handler: { [weak self] (_) in
            self?._popup()
        }))
        alert.addAction(UIAlertAction(title: Strings.no, style: UIAlertAction.Style.cancel, handler: nil))
        present(alert, animated: true, completion: nil)
    }
    
    // 设置按钮点击事件
    @objc private func _studySettingsButtonTapped() {
        let vc = StudySettingsViewController()
        navigationController?.pushViewController(vc, animated: true)
    }
    
    // 报警通知
    @objc private func _handelTriggerAlarmNotification(_ note: Notification) {
        guard !isAlarming else { return }
        guard let poseType = note.userInfo?[StudyStateMachine.triggerAlarmNoteKeyPoseType] as? PoseType,
            !poseType.isOk else {
            return
        }
        isAlarming = true
        ttsEngine.speak(TTSSpeechUtterance.plainText(poseType.description))
        _sendEMMessage(poseType.description)
        isAlarming = false
    }
    
}
